// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 

using System;
using System.Threading;
using System.Collections.Generic;

using Galaxium.Protocol.Xmpp.Library.Messaging;
using Galaxium.Protocol.Xmpp.Library.Core;
using Galaxium.Protocol.Xmpp.Library.Utility;

using Anculus.Core;

namespace Galaxium.Protocol.Xmpp.Library.Helpers
{
	public enum AlertType {
		ActiveChat, InactiveChat, Message, SubsRequest
	}
	
	public enum NotificationType {
		Chat, Message, SubsRequest
	}
	
	public delegate void AlertHandler (AlertType type, Contact contact, object argument);
	public delegate void NotificationHandler (NotificationType type, Contact contact);
	
	public class NotificationHelper
	{
		private Client _client;

		public event AlertHandler        AlertEvent          = delegate {};
		public event NotificationHandler NotificationEvent   = delegate {};
		public event NotificationHandler UnnotificationEvent = delegate {};
			
		public NotificationHelper (Client client)
		{
			_client = client;
			
			RegisterChatNotifications ();
			RegisterMessageNotifications ();
			RegisterStateNotifications ();
			RegisterSubscriptionNotifications ();
		}

		private void RegisterChatNotifications ()
		{
			var chat_tracker = new HashSet<JabberID> ();
			
			Conversation.MessageReceived += (sender, e) => {
				var conversation = sender as Conversation;
				CallAlert (conversation.Active ? AlertType.ActiveChat :
				           AlertType.InactiveChat, conversation.Contact, e.Message);
				if (conversation.Active || chat_tracker.Contains (conversation.Jid)) return;
				
				if (chat_tracker.Count == 0)
					StartNotification (NotificationType.Chat, null);
				chat_tracker.Add (conversation.Jid);
				StartNotification (NotificationType.Chat, conversation.Contact);
			};

			Conversation.ChatActivated += (sender, e) => {
				var conversation = sender as Conversation;
				if (!chat_tracker.Contains (conversation.Jid)) return;
				chat_tracker.Remove (conversation.Jid);
				EndNotification (NotificationType.Chat, conversation.Contact);
				if (chat_tracker.Count == 0)
					EndNotification (NotificationType.Chat, null);
			};
		}
		
		private void RegisterMessageNotifications ()
		{
			var message_tracker = new HashSet<int> ();

			_client.MessageManager.NewMessageEvent += (message_id) => {
				var message_head = _client.MessageManager.GetMessage (message_id);
				CallAlert (AlertType.Message,
				           _client.Roster.GetContact (message_head.Contact),
				           message_head);
				if (message_head.IsOutgoing) return; // alert, but no notification for sent messages
				message_tracker.Add (message_head.Id);
				if (message_tracker.Count == 1)
					StartNotification (NotificationType.Message, null);
			};

			_client.MessageManager.MessageShownEvent += (message_id) => {
				if (!message_tracker.Contains (message_id)) return;
				message_tracker.Remove (message_id);
				if (message_tracker.Count == 0)
					EndNotification (NotificationType.Message, null);
			};
		}
		
		private void RegisterStateNotifications ()
		{
		}
		
		private void RegisterSubscriptionNotifications ()
		{
			var request_tracker = new HashSet<JabberID> ();

			// TODO: some anti-spam precautions perhaps
			
			_client.Roster.SubscriptionRequested += (sender, e) => {
				CallAlert (AlertType.SubsRequest, e.Contact, e.Message);
				if (request_tracker.Count == 0)
					StartNotification (NotificationType.SubsRequest, null);
				request_tracker.Add (e.Contact.Jid);
				StartNotification (NotificationType.SubsRequest, e.Contact);
			};
			
		//	_client.Roster.SubscriptionRequestHandledEvent += delegate (Contact contact) {
		//		if (!request_tracker.Contains (contact.Jid)) return;
		//		request_tracker.Remove (contact.Jid);
		//		EndNotification (NotificationType.SubsRequest, contact);
		//		if (request_tracker.Count == 0)
		//			EndNotification (NotificationType.SubsRequest, null);
		//	};
		}

		private void CallAlert (AlertType type, Contact contact, object argument)
		{
			var message = (contact == null) ? ("Global alert (" + type.ToString () + ")") :
				("Alert ("+type.ToString ()+") from contact " + contact.Jid);
			Log.Debug (message);
			
			AlertEvent (type, contact, argument);
		}		

		private void StartNotification (NotificationType type, Contact contact)
		{
			var jid = contact == null ? "GLOBAL" : (string) contact.Jid;
			Log.Debug ("Notification (" + type.ToString () + ") for contact " + jid);
		//	if (contact != null)
		//		contact.PendingEvents.Add (type);
			// FIXME: notifications
			NotificationEvent (type, contact);
		}

		private void EndNotification (NotificationType type, Contact contact)
		{
			var jid = contact == null ? "GLOBAL" : (string) contact.Jid;
			Log.Debug ("Unotification (" + type.ToString () + ") for contact " + jid);
		//	if (contact != null)
		//		contact.PendingEvents.Remove (type);
			UnnotificationEvent (type, contact);
		}
	}
}
